package com.project.frba.bifront.client.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.user.client.rpc.IsSerializable;

public class DataNode implements IsSerializable{
	
	private String nodeValue;
	private Integer level;
	private Map<String, DataNode> childNodes = new HashMap<String, DataNode>();
	private Integer indexRow;
	private Integer indexCol;
	private Integer realIndex;
	private Boolean isSpanned = false;
	private String propertyName;
	private DataNode parent;
	

	public DataNode(){
		
	}
	
	public DataNode getParent() {
		return parent;
	}
	
	public void setParent(DataNode parent) {
		this.parent = parent;
	}
	
	public Integer getLevel() {
		return level;
	}
	
	public void setSpanned(){
		this.isSpanned = true;
	}
	
	public Boolean isSpanned(){
		return this.isSpanned;
	}
	
	public Boolean isSpanneable(){
		if(!this.isLeaf()){
			return true;
		}
		return false;
	}
	
	public void setLevel(Integer level) {
		this.level = level;
	}
	
	public Integer getIndexRow(){
		return this.indexRow;
	}
	
	public void setIndexRow(Integer index){
		this.indexRow = index;
	}


	public void setNodeValue(String value){
		this.nodeValue = value;
	}
	
	public DataNode addChildNode(String value, String propertyName){
		DataNode newNode = new DataNode();
		newNode.setNodeValue(value);
		newNode.setPropertyName(propertyName);
		newNode.setLevel(this.getLevel() + 1);
		newNode.setParent(this);
		if(!childNodes.containsKey(value)){
			this.childNodes.put(value, newNode);
		}
		return this.childNodes.get(value);
	}
	
	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}

	public String getNodeValue(){
		return this.nodeValue;
	}
	
	public Integer getLeafSize(){
		if(this.isLeaf()){
			return 1;
		}
		Integer amount = 0;
		for (String value: childNodes.keySet()) {
			amount += childNodes.get(value).getLeafSize();
		}
		
		return amount;
	}
	
	@Override
	public boolean equals(Object node) {
		if (this.nodeValue == ((DataNode)node).getNodeValue()) {
			return true;
		}
		return false;
	}
	
	@Override
	public String toString() {
		StringBuffer buff = new StringBuffer(this.nodeValue);
		for (String child : childNodes.keySet()) {
			buff.append("\t" + childNodes.get(child));
			buff.append("\n");
		}
		
		
		
		return buff.toString();
	}

	public List<DataNode> getNodesForLevel(Integer level) {
		List<DataNode> levelNodes = new ArrayList<DataNode>();
		if(this.getLevel().equals(level)){
			levelNodes.add(this);
		} else {
			for (String value : childNodes.keySet()) {
				levelNodes.addAll(childNodes.get(value).getNodesForLevel(level));
			}
		}
		return levelNodes;
	}
	
	public List<DataNode> getAllNodes(){
		List<DataNode> allNodes = new ArrayList<DataNode>();
		DataNode previousNode = null;
		for (String value : childNodes.keySet()) {
			DataNode node = childNodes.get(value);
			if(previousNode == null){
				node.setIndexRow(this.getIndexRow());
				node.setIndexCol(this.indexCol + 1);
			} else {
				Integer lastNodeIndex = allNodes.size() - 1;
				DataNode lastNode = allNodes.get(lastNodeIndex);
				node.setIndexRow(lastNode.getIndexRow() + 1);
				node.setIndexCol(0);
			}
			allNodes.add(node);
			previousNode = node;
			allNodes.addAll(node.getAllNodes());
		}
		
		return allNodes;
	}
	
	public Boolean isLeaf(){
		if(this.childNodes.size() == 0){
			return true;
		}
		return false;
	}

	public DataNode getNodeByValues(List<String> values) {
		if(this.isLeaf()){
			return this;
		}
		DataNode childNode = childNodes.get(values.get(this.getLevel()+1));
		
		return childNode.getNodeByValues(values);
		
	}

	public String getPropertyName() {
		return this.propertyName;
	}

	public void setIndexCol(Integer index) {
		this.indexCol = index;
		
	}
	
	public Integer getIndexCol(){
		return this.indexCol;
	}

	public Integer getRealIndex() {
		return realIndex;
	}

	public void setRealIndex(Integer realIndex) {
		this.realIndex = realIndex;
	}

}
